home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / osrc.arc / KERNEL.C < prev    next >
Encoding:
C/C++ Source or Header  |  1989-05-27  |  11.2 KB  |  472 lines

  1. /* Non pre-empting synchronization kernel, machine-independent portion */
  2. #if    defined(PROCLOG) || defined(PROCTRACE)
  3. #include <stdio.h>
  4. #endif
  5. #include <dos.h>
  6. #include <setjmp.h>
  7. #include "global.h"
  8. #include "mbuf.h"
  9. #include "proc.h"
  10.  
  11. #ifdef    PROCLOG
  12. FILE *proclog;
  13. FILE *proctrace;
  14. #endif
  15. int Stkchk = 0;
  16. struct proc *Curproc;        /* Currently running process */
  17. struct proc *Rdytab;        /* Processes ready to run (not including curproc) */
  18. struct proc *Waittab[PHASH];    /* Waiting process list */
  19. struct proc *Susptab;        /* Suspended processes */
  20. struct mbuf *Killq;
  21. static void addproc(),delproc();
  22. static unsigned phash();
  23.  
  24. /* Create a process descriptor for the main function. Must be actually
  25.  * called from the main function!
  26.  */
  27. struct proc *
  28. mainproc(name)
  29. char *name;
  30. {
  31.     register struct proc *pp;
  32.  
  33.     /* Create process descriptor */
  34.     if((pp = (struct proc *)calloc(1,sizeof(struct proc))) == NULLPROC)
  35.         return NULLPROC;
  36.  
  37.     /* Create name */
  38.     pp->name = strdup(name);
  39.     pp->stksize = 65535;
  40.     psetup(pp,0,NULL,NULL,NULLVFP);
  41.  
  42.     /* Make current */
  43.     pp->state = READY;
  44.     Curproc = pp;
  45.  
  46. #ifdef    PROCLOG
  47.     proclog = fopen("proclog",APPEND_TEXT);
  48.     proctrace = fopen("proctrace",APPEND_TEXT);
  49. #endif
  50.     return pp;
  51. }
  52. /* Create a new, ready process and return pointer to descriptor.
  53.  * The general registers are not initialized, but optional args are pushed
  54.  * on the stack so they can be seen by a C function.
  55.  */
  56. struct proc *
  57. newproc(name,stksize,pc,iarg,parg1,parg2)
  58. char *name;        /* Arbitrary user-assigned name string */
  59. unsigned int stksize;    /* Stack size in words to allocate */
  60. void (*pc)();        /* Initial execution address */
  61. int iarg;        /* Integer argument (argc) */
  62. void *parg1;        /* Generic pointer argument #1 (argv) */
  63. void *parg2;        /* Generic pointer argument #2 (session ptr) */
  64. {
  65.     register struct proc *pp;
  66.     int i;
  67.  
  68.     if(Stkchk)
  69.         chkstk();
  70.  
  71.     /* Create process descriptor */
  72.     if((pp = (struct proc *)calloc(1,sizeof(struct proc))) == NULLPROC)
  73.         return NULLPROC;
  74.  
  75.     /* Create name */
  76.     pp->name = strdup(name);
  77.  
  78.     /* Allocate stack */
  79.     pp->stksize = stksize;
  80.     if((pp->stack = (int16 *)malloc(sizeof(int16)*stksize)) == NULL){
  81.         free(pp->name);
  82.         free((char *)pp);
  83.         return NULLPROC;
  84.     }
  85.     /* Initialize stack for high-water check */
  86.     for(i=0;i<stksize;i++)
  87.         pp->stack[i] = STACKPAT;
  88.  
  89.     /* Do machine-dependent initialization of stack */
  90.     psetup(pp,iarg,parg1,parg2,pc);
  91.  
  92.     /* Add to ready process table */
  93.     pp->state = READY;
  94.     addproc(pp);
  95.     return pp;
  96. }
  97.  
  98. /* Free resources allocated to specified process. If a process wants to kill
  99.  * itself, the reaper is called to do the dirty work. This avoids some
  100.  * messy situations that would otherwise occur, like freeing your own stack.
  101.  */
  102. void
  103. killproc(pp)
  104. register struct proc *pp;
  105. {
  106.     if(pp == NULLPROC)
  107.         return;
  108.     /* Don't check the stack here! Will cause infinite recursion if
  109.      * called from a stack error
  110.      */
  111.  
  112.     if(pp == Curproc)
  113.         killself();    /* Doesn't return */
  114.  
  115.     /* Close any open sockets */
  116.     freesock(pp);
  117.  
  118.     /* Stop alarm clock in case it's running */
  119.     stop_timer(&pp->alarm);
  120.  
  121.     /* Alert everyone waiting for this proc to die */
  122.     psignal(pp,0);
  123.  
  124.     /* Remove from appropriate table */
  125.     delproc(pp);
  126.  
  127. #ifdef    PROCLOG
  128.     fprintf(proclog,"id %lx name %s stack %u/%u\n",ptol(pp),
  129.         pp->name,stkutil(pp),pp->stksize);
  130.     fclose(proclog);
  131.     proclog = fopen("proclog",APPEND_TEXT);
  132.     proctrace = fopen("proctrace",APPEND_TEXT);
  133. #endif
  134.     /* Free allocated memory resources */
  135.     free(pp->name);
  136.     free(pp->stack);
  137.     free((char *)pp);
  138. }
  139. /* Terminate current process by sending a request to the killer process.
  140.  * Automatically called when a process function returns. Does not return.
  141.  */
  142. void
  143. killself()
  144. {
  145.     register struct mbuf *bp;
  146.  
  147.     if(Curproc != NULLPROC){
  148.         bp = pushdown(NULLBUF,sizeof(Curproc));
  149.         memcpy(bp->data,(char *)&Curproc,sizeof(Curproc));
  150.         enqueue(&Killq,bp);
  151.     }
  152.     /* "Wait for me; I will be merciful and quick." */
  153.     for(;;)
  154.         pwait(NULL);
  155. }
  156. /* Process used by processes that want to kill themselves */
  157. void
  158. killer()
  159. {
  160.     struct proc *pp;
  161.     struct mbuf *bp;
  162.  
  163.     for(;;){
  164.         while(Killq == NULLBUF)
  165.             pwait(&Killq);
  166.         bp = dequeue(&Killq);
  167.         pullup(&bp,(char *)&pp,sizeof(pp));
  168.         free_p(bp);
  169.         if(pp != Curproc)    /* We're immortal */
  170.             killproc(pp);
  171.     }                        
  172. }
  173.  
  174. /* Inhibit a process from running */
  175. void
  176. suspend(pp)
  177. struct proc *pp;
  178. {
  179.     if(pp == NULLPROC)
  180.         return;
  181.     if(pp != Curproc)
  182.         delproc(pp);    /* Running process isn't on any list */
  183.     pp->state |= SUSPEND;
  184.     if(pp != Curproc)
  185.         addproc(pp);    /* pwait will do it for us */
  186.     else
  187.         pwait(NULL);
  188. }
  189. /* Restart suspended process */
  190. void
  191. resume(pp)
  192. struct proc *pp;
  193. {
  194.     if(pp == NULLPROC)
  195.         return;
  196.     delproc(pp);    /* Can't be Curproc! */
  197.     pp->state &= ~SUSPEND;
  198.     addproc(pp);
  199. }
  200.  
  201. /* Wakeup waiting process, regardless of event it's waiting for. The process
  202.  * will see a return value of "val" from its pwait() call.
  203.  */
  204. void
  205. alert(pp,val)
  206. struct proc *pp;
  207. int val;
  208. {
  209.     if(pp == NULLPROC)
  210.         return;
  211.     if((pp->state & WAITING) == 0)
  212.         return;
  213. #ifdef    PROCTRACE
  214.     printf("alert(%lx,%u) [%s]\n",ptol(pp),val,pp->name);
  215.     fflush(stdout);
  216. #endif
  217.     if(pp != Curproc)
  218.         delproc(pp);
  219.     pp->state &= ~WAITING;
  220.     pp->retval = val;
  221.     pp->event = 0;
  222.     addproc(pp);
  223. }
  224.  
  225. /* Post a wait on a specified event and give up the CPU until it happens. The
  226.  * null event is special: it means "I don't want to block on an event, but let
  227.  * somebody else run for a while". It can also mean that the present process
  228.  * is terminating; in this case the wait never returns.
  229.  *
  230.  * Pwait() returns 0 if the event was signaled; otherwise it returns the
  231.  * arg in an alert() call. Pwait must not be called from interrupt level.
  232.  */
  233. int
  234. pwait(event)
  235. void *event;
  236. {
  237.     struct proc *oldproc;
  238.     char i_state;
  239.     extern int Tick;
  240.     int tmp;
  241.  
  242.     i_state = dirps();
  243.     if(Curproc != NULLPROC){    /* If process isn't terminating */
  244.         if(Stkchk)
  245.             chkstk();
  246.  
  247.         if(event == NULL){
  248.             /* Special case; just give up the processor.
  249.              *
  250.              * Optimization: if nothing else is ready, just return.
  251.              */
  252.             if(Rdytab == NULLPROC){
  253.                 restore(i_state);
  254.                 return 0;
  255.             }
  256.         } else {
  257.             /* Post a wait for the specified event */
  258.             Curproc->event = event;
  259.             Curproc->state = WAITING;
  260.         }
  261.         addproc(Curproc);
  262.     }
  263.     /* Look for a ready process and run it. If there are none,
  264.      * loop or halt until an interrupt makes something ready.
  265.      */
  266.     while(Rdytab == NULLPROC){
  267.         /* give system back to upper-level multitasker, if any */
  268.         giveup();
  269.     }
  270.     /* Remove first entry from ready list */
  271.     oldproc = Curproc;
  272.     Curproc = Rdytab;
  273.     delproc(Curproc);
  274.  
  275.     /* Now do the context switch.
  276.      * This technique was inspired by Rob, PE1CHL, and is a bit tricky.
  277.      *
  278.      * If the old process has gone away, simply load the new process's
  279.      * environment. Otherwise, save the current process's state. Then if
  280.      * this is still the old process, load the new environment. Since the
  281.      * new task will "think" it's returning from the setjmp() with a return
  282.      * value of 1, the comparison with 0 will bypass the longjmp(), which
  283.      * would otherwise cause an infinite loop.
  284.      */
  285. #ifdef    PROCTRACE
  286.     if(strcmp(oldproc->name,Curproc->name) != 0){
  287.           printf("-> %s(%d)\n",Curproc->name,Curproc->i_state);
  288.         fflush(stdout);
  289.     }
  290. #endif
  291.     /* Note use of comma operator to save old interrupt state only if
  292.      * oldproc is non-null
  293.      */
  294.     if(oldproc == NULLPROC
  295.      || (oldproc->i_state = i_state, setjmp(oldproc->env) == 0)){
  296.         /* We're still running in the old task; load new task context.
  297.          * The interrupt state is restored here in case longjmp
  298.          * doesn't do it (e.g., systems other than Turbo-C).
  299.          */
  300.         restore(Curproc->i_state);
  301.         longjmp(Curproc->env,1);
  302.     }
  303.     /* At this point, we're running in the newly dispatched task */
  304.     tmp = Curproc->retval;
  305.     Curproc->retval = 0;
  306.  
  307.     /* Also restore the true interrupt state here, in case the longjmp
  308.      * DOES restore the interrupt state saved at the time of the setjmp().
  309.      * This is the case with Turbo-C's setjmp/longjmp.
  310.      */
  311.     restore(Curproc->i_state);
  312.     return tmp;
  313. }
  314.  
  315. /* Make ready the first 'n' processes waiting for a given event. The ready
  316.  * processes will see a return value of 0 from pwait().  Note that they don't
  317.  * actually get control until we explicitly give up the CPU ourselves through
  318.  * a pwait(). Psignal may be called from interrupt level.
  319.  */
  320. void
  321. psignal(event,n)
  322. void *event;    /* Event to signal */
  323. int n;        /* Max number of processes to wake up */
  324. {
  325.     register struct proc *pp;
  326.     struct proc *pnext;
  327.     int i_state;
  328.  
  329.     if(Stkchk)
  330.         chkstk();
  331.  
  332.     if(event == NULL)
  333.         return;        /* Null events are invalid */
  334.  
  335.     /* n = 0 means "signal everybody waiting for this event" */
  336.     if(n == 0)
  337.         n = 65535;
  338.  
  339.     i_state = dirps();
  340.     for(pp = Waittab[phash(event)];n != 0 && pp != NULLPROC;pp = pnext){
  341.         pnext = pp->next;
  342.         if(pp->event == event){
  343. #ifdef    PROCTRACE
  344.             if(i_state){
  345.                 printf("psignal(%lx,%u) wake %lx [%s]\n",ptol(event),n,
  346.                  ptol(pp),pp->name);
  347.                 fflush(stdout);
  348.             }
  349. #endif
  350.             delproc(pp);
  351.             pp->state &= ~WAITING;
  352.             pp->event = 0;
  353.             pp->retval = 0;
  354.             n--;
  355.             addproc(pp);
  356.         }
  357.     }
  358.     for(pp = Susptab;n != 0 && pp != NULLPROC;pp = pnext){
  359.         pnext = pp->next;
  360.         if(pp->event == event){
  361. #ifdef    PROCTRACE
  362.             if(i_state){
  363.                 printf("psignal(%lx,%u) wake %lx [%s]\n",ptol(event),n,
  364.                  ptol(pp),pp->name);
  365.                 fflush(stdout);
  366.             }
  367. #endif
  368.             delproc(pp);
  369.             pp->state &= ~WAITING;
  370.             pp->event = 0;
  371.             pp->retval = 0;
  372.             addproc(pp);
  373.             n--;
  374.         }
  375.     }
  376.     restore(i_state);
  377. }
  378.  
  379. /* Rename a process */
  380. void
  381. chname(pp,newname)
  382. struct proc *pp;
  383. char *newname;
  384. {
  385.     free(pp->name);
  386.     pp->name = strdup(newname);
  387. }
  388. /* Remove a process entry from the appropriate table */
  389. static void
  390. delproc(entry)
  391. register struct proc *entry;    /* Pointer to entry */
  392. {
  393.     int i_state;
  394.  
  395.     if(entry == NULLPROC)
  396.         return;
  397.  
  398.     i_state = dirps();
  399.     if(entry->next != NULLPROC)
  400.         entry->next->prev = entry->prev;
  401.     if(entry->prev != NULLPROC)
  402.         entry->prev->next = entry->next;
  403.     else {
  404.         switch(entry->state){
  405.         case READY:
  406.             Rdytab = entry->next;
  407.             break;
  408.         case WAITING:
  409.             Waittab[phash(entry->event)] = entry->next;
  410.             break;
  411.         case SUSPEND:
  412.         case SUSPEND|WAITING:
  413.             Susptab = entry->next;
  414.             break;
  415.         }
  416.     }
  417.     restore(i_state);
  418. }
  419. /* Append proc entry to end of appropriate list */
  420. static void
  421. addproc(entry)
  422. register struct proc *entry;    /* Pointer to entry */
  423. {
  424.     register struct proc *pp;
  425.     struct proc **head;
  426.     int i_state;
  427.  
  428.     if(entry == NULLPROC)
  429.         return;
  430.  
  431.     i_state = dirps();
  432.     switch(entry->state){
  433.     case READY:
  434.         head = &Rdytab;
  435.         break;
  436.     case WAITING:
  437.         head = &Waittab[phash(entry->event)];
  438.         break;
  439.     case SUSPEND:
  440.     case SUSPEND|WAITING:
  441.         head = &Susptab;
  442.         break;
  443.     }
  444.     entry->next = NULLPROC;
  445.     if(*head == NULLPROC){
  446.         /* Empty list, stick at beginning */
  447.         entry->prev = NULLPROC;
  448.         *head = entry;
  449.     } else {
  450.         /* Find last entry on list */
  451.         for(pp = *head;pp->next != NULLPROC;pp = pp->next)
  452.             ;
  453.         pp->next = entry;
  454.         entry->prev = pp;
  455.     }
  456.     restore(i_state);
  457. }
  458. static unsigned
  459. phash(event)
  460. void *event;
  461. {
  462.     register char *cp = (char *)&event;
  463.     int i = sizeof(event);
  464.     register unsigned x = 0;
  465.  
  466.     while(i-- != 0)
  467.         x ^= *cp++;
  468.  
  469.     return x % PHASH;
  470. }
  471.  
  472.